// ==UserScript==
// @name          NextPlease! for Chrome
// @namespace     http://fanofun.yo2.cn/
// @description   NextPlease! for Chrome. Jump to next and previous links using "rocker gesture". NextPlease! is a great extension for Firefox written by Howie Wang(http://nextplease.mozdev.org/index.html), I(http://fanofun.yo2.cn) just transplanted it to Google Chrome.
// @include       *
// @exclude       http://diveintogreasemonkey.org/*
// @run-at document-start
// @version       0.1
// ==/UserScript==
	
    var useSubmit = false;
    var useNumberShortcuts = true;
    var useContextMenu = true;
    var useSmartNext = false;
    var NEXTPLEASE_MAX_LINK_NUM = 700;
    var NEXTPLEASE_MAX_GALLERY_GAP = 20;
    var NEXTPLEASE_MAX_IMAGE_CACHE = 500;
    
    var NextPhrasesMap = new Array();
    var PrevPhrasesMap = new Array();
    var FirstPhrasesMap = new Array();
    var LastPhrasesMap = new Array();
    
    var NextImagesMap = new Array();
    var PrevImagesMap = new Array();
    var FirstImagesMap = new Array();
    var LastImagesMap = new Array();
    
    var DefaultNextPhrases = new Array("Next", "next", "Next >", "next >", ">", "MORE RESULTS", "Newer »", "Older topics »", "next page", "Go to the next photo in the stream", "下一页");
    var DefaultPrevPhrases = new Array("Previous", "previous", "Prev", "prev", "< Previous", "< previous", "PREVIOUS RESULTS", "< Prev", "< prev", "<", "<< Prev", "« Older", "« Newer topics", "previous page", "Go to the previous photo in the stream", "上一页");
    
    var DefaultFirstPhrases = new Array("First", "first", "< First", "< first", "first page");
    var DefaultLastPhrases = new Array("Last", "last", "Last >", "last >", "last page");
    
    var DefaultNextImages = new Array("http://g-images.amazon.com/images/G/01/search-browse/button-more-results.gif");
    var DefaultPrevImages = new Array("http://g-images.amazon.com/images/G/01/search-browse/button-previous.gif");
    var DefaultFirstImages = new Array();
    var DefaultLastImages = new Array();
    
    var DefaultNextRegEx = "^next(\\s+\\d+)?(\\s+\\w+)?\\s*((>?>?)|\\xbb)\\s*\$";
    var DefaultPrevRegEx = "^((<?<?)|\\xab)\\s*((prev(ious)?(\\s+\\d+)?(\\s+\\w+)?)|back)\\s*\$";
    var DefaultFirstRegEx = "^((<?<?)|\\xab)\\s*(first(\\s+\\d+)?(\\s+\\w+)?)\\s*$";
    var DefaultLastRegEx = "^last(\\s+\\d+)?(\\s+\\w+)?\\s*((>?>?)|\\xbb)\\s*$";
    
    var OldDefaultGalleryRegEx = ".*?(\\d+)[^/]*?\\.(?:jpg|gif|bmp|png)$";
    var DefaultGalleryRegEx = "(.*(?:[^\\d]|^))(\\d+)([^/]*?\\.(?:jpg|gif|bmp|png))$";
    
    
    NextPhrasesMap = nextplease_initializeNextPrevMap('nextplease.nextphrase', DefaultNextPhrases);
    PrevPhrasesMap = nextplease_initializeNextPrevMap('nextplease.prevphrase', DefaultPrevPhrases);
    FirstPhrasesMap = nextplease_initializeNextPrevMap('nextplease.firstphrase', DefaultFirstPhrases);
    LastPhrasesMap = nextplease_initializeNextPrevMap('nextplease.lastphrase', DefaultLastPhrases);
    
    NextImagesMap = nextplease_initializeNextPrevMap('nextplease.nextimage', DefaultNextImages);
    PrevImagesMap = nextplease_initializeNextPrevMap('nextplease.previmage', DefaultPrevImages);
    FirstImagesMap = nextplease_initializeNextPrevMap('nextplease.firstimage', DefaultFirstImages);
    LastImagesMap = nextplease_initializeNextPrevMap('nextplease.lastimage', DefaultLastImages);
    
    isNextRegExp = new RegExp(DefaultNextRegEx, "i");
    isPrevRegExp = new RegExp(DefaultPrevRegEx, "i");
    isFirstRegExp = new RegExp(DefaultFirstRegEx, "i");
    isLastRegExp = new RegExp(DefaultLastRegEx, "i");
    galleryRegExString = DefaultGalleryRegEx;
    galleryUrlRegex = new RegExp(DefaultGalleryRegEx, "i");
    NEXT_SEARCH_TYPE = 1;
    PREV_SEARCH_TYPE = 2;
    FIRST_SEARCH_TYPE = 3;
    LAST_SEARCH_TYPE = 4;
    
    
    // Read the phrases that specify a next link
    // by reading the preferences or defaults,
    // and put the phrases in a lookup table.
    function nextplease_initializeNextPrevMap(prefbranch, DefaultArray){
        //    var nextpleasePrefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("");
        
        var Map = new Array();
        //    if (nextpleasePrefs.prefHasUserValue(prefbranch + '.expr0')) {
        if (false) {
            var tempprefname = prefbranch + '.expr0';
            var i = 0;
            while (nextpleasePrefs.prefHasUserValue(tempprefname)) {
                //	    var phrase = nextpleasePrefs.getCharPref(tempprefname);
                var prefValue = nextplease_GetUnicharPref(nextpleasePrefs, tempprefname, Components.interfaces.nsISupportsString);
                var values = prefValue.split("|");
                for (var j = 0; j < values.length; j++) {
                    var phrase = values[j].replace(/&pipe;/g, "|");
                    if (phrase != '') {
                        Map[phrase] = true;
                    }
                }
                i++;
                tempprefname = prefbranch + '.expr' + i;
            }//if
        }
        else {
            for (var i = 0; i < DefaultArray.length; i++) {
                Map[DefaultArray[i]] = true;
            }
        }
        return Map;
    }
    
    // Strip leading and trailing whitespace from
    // the passed in string and return it.
    function nextplease_Trim(str){
        return str.replace(/^\s*|\s*$/g, "");
    }
    
    // Looks through all the links on the page
    // and tries to look for one whose text matches
    // one of the phrases or images. If so, it goes to/
    // the corresponding link. 
    // pages with frames.
    function nextplease_getLink(curWindow, phraseMap, imageMap, phraseRegEx, searchType){
        var text;
        var isInt = /^\s*\[?\s*(\d+)\s*\]?\s*$/;
        var useFrames = true;
        
        var tmpPageNumLink = null;
        var firstPageNumLink = null;
        var firstPageNum;
        var lastPageNumLink = null;
        var nextPageNumLink = null;
        var prevPageNumLink = null;
        
        var currentPageNum = 100000; // Init to arbitrarily large num
        var tmpPageNum = 100000;// Init to arbitrarily large num
        var isFirstNumber = true;
        var greatestNum = 1;
        
        //    nextplease_readPreferences();
        
        var range = document.createRange();
        
        // deleted by Fanofun
        //    if (useSmartNext) {
        //    	if ((searchType == NEXT_SEARCH_TYPE) &&
        //    	    (getBrowser().canGoForward)) {
        //    	    return curWindow.history.forward();
        //    	} else if ((searchType == PREV_SEARCH_TYPE) &&
        //    		   (getBrowser().canGoBack)) {
        //    	    return curWindow.history.back();
        //    	}
        //    }
        
        // Look for <LINK> tags
        var linktags = curWindow.document.getElementsByTagName("LINK");
        
        for (var i = 0; i < linktags.length; i++) {
            var link = linktags[i];
            
            // Look for rel attributes for next/prev/first/last
            if (link.rel) {
                // Hack to workaround PHPBB's incorrect use of LINK tags.
                if (curWindow.location.href.match("viewtopic.php")) {
                    // do nothing
                }
                else 
                    if ((searchType == NEXT_SEARCH_TYPE) &&
                    (link.rel.toLowerCase() == "next")) {
                        return nextplease_openLink(curWindow, link);
                    }
                    else 
                        if ((searchType == PREV_SEARCH_TYPE) &&
                        ((link.rel.toLowerCase() == "prev") ||
                        (link.rel.toLowerCase() == "previous"))) {
                            return nextplease_openLink(curWindow, link);
                        }
                        else 
                            if ((searchType == FIRST_SEARCH_TYPE) &&
                            ((link.rel.toLowerCase() == "start") ||
                            (link.rel.toLowerCase() == "first"))) {
                                return nextplease_openLink(curWindow, link);
                            }
                            else 
                                if ((searchType == LAST_SEARCH_TYPE) &&
                                ((link.rel.toLowerCase() == "end") ||
                                (link.rel.toLowerCase() == "last"))) {
                                    return nextplease_openLink(curWindow, link);
                                }
            }
        }
        
        // Look for <A HREF="..."> tags
        var alinks = curWindow.document.links;
        
        // Search through each link
        for (var i = 0; i < alinks.length; i++) {
            var link = alinks[i];
            // Look for rel attributes for next/prev/first/last
            if (link.rel) {
                if ((searchType == NEXT_SEARCH_TYPE) &&
                (link.rel.toLowerCase() == "next")) {
                    return nextplease_openLink(curWindow, link);
                }
                else 
                    if ((searchType == PREV_SEARCH_TYPE) &&
                    ((link.rel.toLowerCase() == "prev") ||
                    (link.rel.toLowerCase() == "previous"))) {
                        return nextplease_openLink(curWindow, link);
                    }
                    else 
                        if ((searchType == FIRST_SEARCH_TYPE) &&
                        ((link.rel.toLowerCase() == "start") ||
                        (link.rel.toLowerCase() == "first"))) {
                            return nextplease_openLink(curWindow, link);
                        }
                        else 
                            if ((searchType == LAST_SEARCH_TYPE) &&
                            ((link.rel.toLowerCase() == "end") ||
                            (link.rel.toLowerCase() == "last"))) {
                                return nextplease_openLink(curWindow, link);
                            }
            }
            range.selectNode(link);
            text = nextplease_Trim(range.toString());
            
            // If the text is in the lookup table,
            // go to the URL
            if (phraseMap[text] == true) {
                // alert('found phrase match');
                if (link.href.indexOf("/dictionary") < 0) {
                    return nextplease_openLink(curWindow, link);
                }
            }
            else {
                // If we don't have an exact match, 
                // try a regular expression test.
                // alert(text);
                if (phraseRegEx.test(text)) {
                    if (link.href.indexOf("/dictionary") < 0) {
                        return nextplease_openLink(curWindow, link);
                    }
                }
                else 
                    if (link.title) {
                        if (phraseRegEx.test(link.title)) {
                            return nextplease_openLink(curWindow, link);
                        }
                    }
                
                // See if there's an image tag
                var imgElems = link.getElementsByTagName("img");
                if (imgElems.length > 0) {
                    // If the image matches, go to the URL.
                    //alert(imgElems[0].src);
                    var imgtext = imgElems[0].alt;
                    if (!imgtext) 
                        imgtext = imgElems[0].title;
                    
                    if ((imageMap[imgElems[0].src]) ||
                    (phraseMap[imgtext] == true) ||
                    (phraseRegEx.test(imgtext))) {
                        //  alert('found image match');	
                        return nextplease_openLink(curWindow, link);
                    }
                }
            }
            
            var intMatches = isInt.exec(text);
            if (intMatches) {
                var linkPageNum = parseInt(intMatches[1]);
                // If the number is greater than a NEXTPLEASE_MAX_LINK_NUM
                // it probably doesn't have anything to do with
                // a next/prev link.
                // 	    alert(linkPageNum);
                if (linkPageNum < NEXTPLEASE_MAX_LINK_NUM) {
                
                    // Try to figure out what the current page and
                    // next/prev links are for pages that just have
                    // numbered links like  1 2 x 4 5. 
                    
                    //		if (linkPageNum == 1) {
                    
                    // We're seeing a number link that is smaller
                    // than a previous one so assume that we're
                    // starting a new set of number links, and
                    // count from the beginning.
                    if (linkPageNum <= tmpPageNum) {
                        //		    alert(linkPageNum);
                        //		    alert(currentPageNum);
                        firstPageNumLink = link;
                        firstPageNum = linkPageNum;
                        greatestNum = linkPageNum;
                        
                        prevPageNumLink = null;
                        nextPageNumLink = null;
                        lastPageNumLink = null;
                        currentPageNum = linkPageNum;
                        
                        firstPageNumLink = link;
                        greatestNum = linkPageNum;
                        lastPageNumLink = null;
                        //		} else if (currentPageNum == linkPageNum) {
                        //		    currentPageNum++;
                        //		    prevPageNumLink = link;
                    }
                    else 
                        if (tmpPageNum + 1 == linkPageNum) {
                            lastPageNumLink = link;
                        }
                        else 
                            if (tmpPageNum + 2 == linkPageNum) {
                                prevPageNumLink = tmpPageNumLink;
                                nextPageNumLink = link;
                                lastPageNumLink = link;
                            }
                    
                    tmpPageNum = linkPageNum;
                    tmpPageNumLink = link;
                }
            }
        }
        
        
        
        // next and prev are null so that means
        // we have a solid block of number 3,4,5,6,...
        if ((nextPageNumLink == null) &&
        (prevPageNumLink == null)) {
        
            // If we start with 1, we're probably on last page.
            // Set prev to be lastPage	
            if (firstPageNum == 1) {
                prevPageNumLink = lastPageNumLink;
                lastPageNumLink = null;
            }
            // If we start with 2, we're probably on first page.
            // Set next to be first page
            if (firstPageNum == 2) {
                nextPageNumLink = firstPageNumLink;
                firstPageNumLink = null;
            }
            if (firstPageNum > 2) {
                nextPageNumLink = firstPageNumLink;
                prevPageNumLink = lastPageNumLink;
            }
        }
        
        if (firstPageNumLink && lastPageNumLink &&
        (firstPageNumLink.text == lastPageNumLink.text)) 
            firstPageNumLink = null;
        
        //    alert(firstPageNumLink);
        //    alert(prevPageNumLink);
        //    alert(nextPageNumLink);
        //    alert(lastPageNumLink);
        
        // Try to find a match using our number algorithm
        if ((searchType == NEXT_SEARCH_TYPE) && nextPageNumLink) 
            return nextplease_openLink(curWindow, nextPageNumLink);
        else 
            if ((searchType == PREV_SEARCH_TYPE) && prevPageNumLink) 
                return nextplease_openLink(curWindow, prevPageNumLink);
            else 
                if ((searchType == FIRST_SEARCH_TYPE) && firstPageNumLink) 
                    return nextplease_openLink(curWindow, firstPageNumLink);
                else 
                    if ((searchType == LAST_SEARCH_TYPE) && lastPageNumLink) 
                        return nextplease_openLink(curWindow, lastPageNumLink);
        
        // Otherwise try looking for next/prev submit buttons 
        // if the user allows it.
        if (useSubmit && nextplease_getForm(phraseMap, phraseRegEx)) 
            return true;
        
        // See if we can increment the URL to get to next/prev/first
        var galleryLink = nextplease_getGalleryNumberLink(curWindow, searchType);
        //	alert(galleryLink);
        //	alert(nextplease_imageLocationArray.length);
        if (galleryLink) 
            curWindow.open(galleryLink, "_self", "");
        
        
        // None of it worked, so make a recursive call to
        // nextplease_getLink on the frame windows.
        var frames = curWindow.frames;
        for (var j = 0; j < frames.length; j++) {
            if (nextplease_getLink(frames[j], phraseMap, imageMap, phraseRegEx, searchType)) 
                return true;
        }
        return false;
    }
    
    function nextplease_getGalleryNumberLink(curWindow, searchType){
        var galleryUrlRegex = new RegExp(galleryRegExString, "i");
        //	alert(nextplease_imageLocationArray);
        
        var matches = galleryUrlRegex.exec(unescape(curWindow.location.href));
        if (matches && (matches.length == 4)) {
            var prefixUrl = matches[1];
            var suffixUrl = matches[3];
            if (searchType == NEXT_SEARCH_TYPE) {
                var curNumber = parseInt(matches[2], 10);
                for (var i = 1; i < NEXTPLEASE_MAX_GALLERY_GAP; i++) {
                    var urlNumber = curNumber + i;
                    var padStr = nextplease_padNumber(matches[2], urlNumber);
                    var linkUrl = prefixUrl + padStr + suffixUrl;
                    if (nextplease_imageLocationMap[linkUrl] >= 0) {
                        return linkUrl;
                    }
                }
                var urlNumber = curNumber + 1;
                var padStr = nextplease_padNumber(matches[2], urlNumber);
                var linkUrl = prefixUrl + padStr + suffixUrl;
                return linkUrl;
            }
            else 
                if (searchType == PREV_SEARCH_TYPE) {
                    var curNumber = parseInt(matches[2], 10);
                    for (var i = 1; (i < NEXTPLEASE_MAX_GALLERY_GAP) && (curNumber - i >= 0); i++) {
                        var urlNumber = curNumber - i;
                        var padStr = nextplease_padNumber(matches[2], urlNumber);
                        var linkUrl = prefixUrl + padStr + suffixUrl;
                        if (nextplease_imageLocationMap[linkUrl] >= 0) {
                            return linkUrl;
                        }
                    }
                    
                    var urlNumber = curNumber - 1;
                    if (urlNumber >= 0) {
                        var padStr = nextplease_padNumber(matches[2], urlNumber);
                        var linkUrl = prefixUrl + padStr + suffixUrl;
                        return linkUrl;
                    }
                }
                else 
                    if (searchType == FIRST_SEARCH_TYPE) {
                        var urlNumber = 1;
                        var padStr = nextplease_padNumber(matches[2], urlNumber);
                        var linkUrl = prefixUrl + padStr + suffixUrl;
                        return linkUrl;
                    }
        }
        return;
    }
    
    function nextplease_openLink(curWindow, linkNode){
        // If it's got an onclick attr, then try to 
        // simulate a mouse click to activate link.
        if (linkNode && linkNode.hasAttribute("onclick")) {
            // alert(linkNode.getAttribute("onclick"));
            var e = document.createEvent("MouseEvents");
            e.initMouseEvent("click", 1, 1, window, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, linkNode);
            linkNode.dispatchEvent(e);
        }
        else {
            curWindow.open(linkNode.href, "_self", "");
        }
        return true;
    }
    
// Automatically find the nextpage link and click it
// Added by Fanofun. Email: wangbida@gmail.com, Blog: http://fanofun.yo2.cn
    function nextplease_findAndClickNextLink(){
        nextplease_getLink(window, NextPhrasesMap, NextImagesMap, isNextRegExp, NEXT_SEARCH_TYPE);
    }
// Automatically find the prevpage link and click it
// Added by Fanofun. Email: wangbida@gmail.com, Blog: http://fanofun.yo2.cn
    function nextplease_findAndClickPrevLink(){
		nextplease_getLink(window, PrevPhrasesMap, PrevImagesMap, isPrevRegExp, PREV_SEARCH_TYPE);
    }
    
    
